package com.goldgov.authentication;

import com.goldgov.kduck.cache.CacheHelper;
import com.kcloud.ms.authentication.baseaccount.service.Account;
import com.kcloud.ms.authentication.baseaccount.service.AccountCredential;
import com.kcloud.ms.authentication.baseaccount.service.AccountCredentialService;
import com.kcloud.ms.authentication.baseaccount.service.AccountService;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.HashSet;
import java.util.Set;

/**
 * 模拟登录验证类
 * @author guor
 */
public class MockLoginAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
    public MockLoginAuthenticationProvider(PasswordEncoder passwordEncoder, AccountService accountService, AccountCredentialService accountCredentialService) {
        this.passwordEncoder = passwordEncoder;
        this.accountCredentialService = accountCredentialService;
        this.accountService=accountService;
    }
    private PasswordEncoder passwordEncoder; //密码加密类
    private AccountService accountService; //账户服务类，用于通过账号获取账户信息
    private AccountCredentialService accountCredentialService; //账号服务类，用于验证账号是否存在

    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    public void setAccountService(AccountService accountService) {
        this.accountService = accountService;
    }

    public void setAccountCredentialService(AccountCredentialService accountCredentialService) {
        this.accountCredentialService = accountCredentialService;
    }

    /**
     * 密码验证类
     * @see org.springframework.security.authentication.dao.DaoAuthenticationProvider
     * @param userDetails 从服务端获取的账户信息对象
     * @param authentication 认证对象
     * @throws AuthenticationException
     */
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            logger.debug("Authentication failed: no credentials provided");

            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    "Bad credentials"));
        }

        String presentedPassword = authentication.getCredentials().toString();
        //密码比对
        if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
            logger.debug("Authentication failed: password does not match stored value");

            throw new BadCredentialsException(messages.getMessage(
                    "AbstractUserDetailsAuthenticationProvider.badCredentials",
                    "Bad credentials"));
        }
    }

    /**
     * 检查账号是否存在，并封装 UserDetails 对象
     * @param username
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected  UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        try {
            UserDetails loadedUser = this.loadUserByUsername(username);
            if (loadedUser == null) {
                throw new InternalAuthenticationServiceException(
                        "UserDetailsService returned null, which is an interface contract violation");
            }
            return loadedUser;
        }
        catch (UsernameNotFoundException ex) {
            throw ex;
        }
        catch (InternalAuthenticationServiceException ex) {
            throw ex;
        }
        catch (Exception ex) {
            throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
        }
    }

    /**
     * 根据登录名查询账户信息，并获取该人员的角色相关信息
     * @param userName 登录名
     * @return
     */
    protected UserDetails loadUserByUsername(String userName){
        AccountCredential accountCredential = accountCredentialService.getCredentialByName(userName);
        if (accountCredential==null){
            throw new UsernameNotFoundException(userName+"不存在。");
        }
        Account account = accountService.getAccount(accountCredential.getAccountId());
        // 增加授权角色，默认为USER，可在此处扩展查询该人员的角色相关信息
        Set<GrantedAuthority> grantedAuths = new HashSet<GrantedAuthority>();
        grantedAuths.add(new SimpleGrantedAuthority("USER"));
        //从缓存中获取模拟密码
        String cachedPwd = CacheHelper.get(userName+"_loginPassword",String.class);
        String loginPassword = passwordEncoder.encode(cachedPwd == null ? System.currentTimeMillis()+"" : cachedPwd);
        User user = new User(userName, loginPassword, !account.getAccountState().equals(Account.ACCOUNT_STATE_DISABLED), true, true, !account.getAccountState().equals(Account.ACCOUNT_STATE_LOCKING), grantedAuths);
        return user;
    }
}
